package io.awen.modules.sign.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.awen.common.exception.RRException;
import io.awen.common.utils.GeoUtils;
import io.awen.common.utils.HttpRequest;
import io.awen.common.utils.PageUtils;
import io.awen.common.utils.Query;
import io.awen.modules.sign.StatusConstants;
import io.awen.modules.sign.dao.SignCarDao;
import io.awen.modules.sign.entity.*;
import io.awen.modules.sign.qo.SignCarModel;
import io.awen.modules.sign.qo.SignCarQo;
import io.awen.modules.sign.service.*;
import io.awen.modules.sys.entity.SysUserEntity;
import io.awen.modules.sys.service.SysUserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;


@Service("signCarService")
public class SignCarServiceImpl extends ServiceImpl<SignCarDao, SignCarEntity> implements SignCarService {

    @Autowired
    private SignCarDao signCarDao;

    @Autowired
    private SignCarSpeedingWarningService signCarSpeedingWarningService;

    @Autowired
    private SignCarWeightChangeService signCarWeightChangeService;
    @Autowired
    private SignCarLoadRecordService signCarLoadRecordService;

    @Autowired
    private SignCarLonLatService signCarLonLatService;

    @Autowired
    private SignFleetService signFleetService;
    @Autowired
    private SignTaskService signTaskService;
    @Autowired
    private SysUserService sysUserService;

    private HashMap<Long, SignCarEntity> carMap;

    private final static Double INIT_LON = 119.824425;
    private final static Double INIT_LAT = 35.958324;

    @PostConstruct
    private void init() {
        carMap = new HashMap<>(50);

        List<SignCarEntity> list = list();
//        Random random = new Random();
        for (SignCarEntity car : list) {

//            SignCarLonLatEntity entity = new SignCarLonLatEntity();
            // 从mangodb/mysql 中获取最新经纬度
//            entity.setLon(INIT_LON - random.nextInt(300) / 1000. * (random.nextInt(1) - 1));
//            entity.setLat(INIT_LAT - random.nextInt(200) / 1000. * (random.nextInt(1) - 1));
//            entity.setSpeed(random.nextInt(700) / 10.);
//            entity.setDirection(276.0);
//            car.setCarLonLat(entity);
            carMap.put(car.getId(), car);
        }
    }

    @Override
    public HashMap<Long, SignCarEntity> getCarMap() {
        return carMap;
    }


    /**
     * 根据车牌号从缓存中获取车辆
     *
     * @param carNumber 车牌号
     * @return
     */
    @Override
    public SignCarEntity getSignCarByCarNumberPlateFromCatch(String carNumber) {

        SignCarEntity byCarNum = getByCarNum(carNumber);
        if (byCarNum == null) {
            throw new RRException("没有维护该车辆");
        }
        return carMap.get(byCarNum.getId());
    }

    /**
     * 清空车辆缓存carMap
     */
    @Override
    public void clearCarMap() {
        this.carMap.clear();
    }

    /**
     * 凌晨1点定时任务，强制将所有车辆状态变为0
     */
    @Override
    public void initCarStatusToNormal() {
        signCarDao.initCarStatusToNormal();
    }


    /**
     * 通过http://112.6.206.206:49111/device/option 获取在线设备数
     *
     * @return
     */
    @Override
    public List<SignCarEntity> getCarInfoFromJtt808() {

        String url = "http://112.6.206.206:49111/device/option";

        String res = HttpRequest.sendGet(url, "");

        JSONArray resultList = null;

        JSONObject resultObject = JSONObject.parseObject(res);
        resultList = resultObject.getJSONArray("data");

        List<SignCarEntity> list = new ArrayList<>();

        if (resultList == null) {
            return list;
        }

        if (resultList != null && resultList.size() > 0) {
            for (int i = 0; i < resultList.size(); i++) {

                JSONObject item = resultList.getJSONObject(i);
                System.out.println(item);

                String clientId = item.getString("mobileNo");
                SignCarEntity signCarByClientId = this.getSignCarByClientId(clientId);
                list.add(signCarByClientId);
            }
        }

        return list;
    }

    @Override
    public SignCarModel getCarCountToday() {
        Collection<SignCarEntity> carList = this.carMap.values();
        int online = 0;
        long minTime = System.currentTimeMillis() - 3600000;
        //建一个数组，储存离线的车辆
        List<SignCarEntity> offlineCarList = new ArrayList<>();
        for (SignCarEntity car : carList) {
            SignCarLonLatEntity carLonLat = car.getCarLonLat();
            if (carLonLat != null && carLonLat.getDataTime().getTime() > minTime) {
                online++;
            } else {
                SignCarLonLatEntity entity = signCarLonLatService.getOne(new QueryWrapper<SignCarLonLatEntity>().eq("car_id", car.getId()).orderByDesc("id").last("limit 1"));
                if (entity == null) {
                    //设置为100年前
                    car.setUpdateTime(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 365 * 100));
                } else {
                    car.setUpdateTime(entity.getDataTime());
                }
                offlineCarList.add(car);
            }

        }
        SignCarModel model = new SignCarModel();
        model.setOnlineCarCount(online);
        model.setOfflineCarCount(carList.size() - online);
        model.setOfflineCarList((ArrayList) offlineCarList);
        return model;
    }


    @Override
    public SignCarEntity getSignCarByClientId(String clientId) {
        return signCarDao.getSignCarByClientId(clientId);
    }


    /**
     * 实时更新
     */
    @Override
    public void updateCarLonLat(SignCarLonLatEntity entity) {
        if (entity.getSpeed() != null && entity.getSpeed() < 2) {
            entity.setSpeed(0.0);
        }

        SignCarEntity car = carMap.get(entity.getCarId());
        if (car == null) {
            car = getById(entity.getCarId());
        }
        if (car == null) {
            return;
        }
        if (entity.getDataTime() == null) {
            entity.setDataTime(new Date());
        }
        entity.setCarPlateNumber(car.getNumberPlate());
        //数据库 sign_car_lon_lat
        signCarLonLatService.save(entity);

        car.setCarLonLat(entity);
        carMap.put(entity.getCarId(), car);

//        如果有任务，更新任务表
//        List<SignTaskEntity> taskList = signTaskService.list(
//                new QueryWrapper<SignTaskEntity>().lambda()
//                        .eq(SignTaskEntity::getDispatchCarId, entity.getCarId())
//                        .eq(SignTaskEntity::getStatus, StatusConstants.TASK_STATUS_PROCESSING)
//        );
//        for (SignTaskEntity task : taskList) {
//            if (StringUtils.isBlank(task.getPath())) {
//                task.setPath("[" + entity.getLon() + "," + entity.getLat() + "]");
//            } else {
//                task.setPath(task.getPath() + ",[" + entity.getLon() + "," + entity.getLat() + "]");
//            }
//        }
//        signTaskService.updateBatchById(taskList);

        //如果超速添加报警记录
        signCarSpeedingWarningService.insertWhenSpeeding(car, entity.getSpeed(), entity.getLon(), entity.getLat());
        signCarLoadRecordService.insertWhenLoadRecord(car, entity.getSpeed(), entity.getWeight(), entity.getLon(), entity.getLat());
    }

    @Override
    public void saveAndCache(SignCarEntity signCar) {
        if (signCar.getLimitSpeed() == null) {
            signCar.setLimitSpeed(60.0);
        }
        save(signCar);
        carMap.put(signCar.getId(), signCar);
    }

    @Override
    public void updateAndCache(SignCarEntity signCar) {
        if (signCar.getLimitSpeed() == null) {
            signCar.setLimitSpeed(60.0);
        }
        updateById(signCar);
        SignCarEntity byId = getById(signCar.getId());
        SignCarEntity car = carMap.get(signCar.getId());
        if (car != null) {
            SignCarLonLatEntity carLonLat = car.getCarLonLat();
            byId.setCarLonLat(carLonLat);
            carMap.put(signCar.getId(), byId);
        }
    }

    @Override
    public SignCarEntity infoByDriver(Long userId) {
        SignCarEntity car = getOne(new QueryWrapper<SignCarEntity>().lambda().eq(SignCarEntity::getDriverId, userId), false);
        if (car == null) {
            throw new RRException("您没有车辆");
        }
        //获取车辆经纬度
        SignCarEntity signCar = findCar(car.getId());
        SignCarLonLatEntity carLonLat = signCarLonLatService.getOne(new QueryWrapper<SignCarLonLatEntity>().eq("car_id", car.getId()).orderByDesc("id").last("limit 1"));

        signCar.setCarLonLat(carLonLat);
        //获取车队信息
        SignFleetEntity fleet = signFleetService.getById(signCar.getFleetId());
        signCar.setFleet(fleet);
        return signCar;
    }

    @Override
    public SignCarEntity findCar(Long carId) {
        SignCarEntity car = carMap.get(carId);
        if (car != null) {
            SignFleetEntity fleet = signFleetService.getById(car.getFleetId());
            car.setFleet(fleet);
            SysUserEntity user = sysUserService.getById(car.getDriverId());
            car.setDriver(user);
            return car;
        } else {
            return null;
        }
    }

    @Override
    public SignCarEntity findNearestCar(SignContainerEntity container) {
//        List<SignCarEntity> carList = list(
//                new QueryWrapper<SignCarEntity>().lambda()
//                        .eq(SignCarEntity::getCtUnitId, container.getCtUnitId())
//        );
//        if (carList.size() == 0) {
//            return null;
//        }
        Iterator<SignCarEntity> iterator = carMap.values().iterator();
        SignCarEntity nearestCar = null;
        Double nearestDistance = Double.MAX_VALUE;
        while (iterator.hasNext()) {
            SignCarEntity car = iterator.next();
            if (car.getCtUnitId().equals(container.getCtUnitId()) && !StatusConstants.CAR_STATUS_STOP.equals(car.getStatus()) && car.getCarLonLat() != null) {
                Double distance = GeoUtils.getDistance(container.getLat(), container.getLon(), car.getCarLonLat().getLat(), car.getCarLonLat().getLon());
                if (nearestDistance > distance) {
                    nearestCar = car;
                }
            }
        }

        return nearestCar;
    }


    @Override
    public int total(SignCarQo qo) {
        int count = this.count(new QueryWrapper<SignCarEntity>().lambda().eq(qo.getCtUnitId() != null, SignCarEntity::getCtUnitId, qo.getCtUnitId()).ge(qo.getStartTime() != null, SignCarEntity::getCreateTime, qo.getStartTime()).le(qo.getEndTime() != null, SignCarEntity::getCreateTime, qo.getEndTime()));
        return count;
    }

    @Override
    public PageUtils queryPage(SignCarQo qo) {
        IPage<SignCarEntity> page = this.page(new Query<SignCarEntity>().getPage(qo), new QueryWrapper<SignCarEntity>().lambda()
//                .like(StringUtils.isNotBlank(qo.getNumberPlate()), SignCarEntity::getNumberPlate, qo.getNumberPlate())
                .eq(qo.getCtUnitId() != null, SignCarEntity::getCtUnitId, qo.getCtUnitId())
                .eq(qo.getFleetId() != null, SignCarEntity::getFleetId, qo.getFleetId())
                .like(StringUtils.isNotBlank(qo.getNumberPlate()), SignCarEntity::getNumberPlate, qo.getNumberPlate())
                .orderByDesc(SignCarEntity::getId));

        for (SignCarEntity entity : page.getRecords()) {
            SysUserEntity user = sysUserService.getById(entity.getDriverId());
            entity.setDriver(user);
        }

        // 实时位置信息

        return new PageUtils(page);
    }

    @Override
    public List<SignCarEntity> realListByQo(SignCarQo qo) {
        Collection<SignCarEntity> cars = carMap.values();
        List<SignCarEntity> carList = new ArrayList<>(cars.size());
        Iterator<SignCarEntity> iterator = cars.iterator();
        while (iterator.hasNext()) {
            SignCarEntity next = iterator.next();
            if (next.getNumberPlate().indexOf(qo.getNumberPlate()) >= 0) {
                carList.add(next);
            }
        }
        return carList;
    }

    @Override
    public SignCarEntity getByCarNum(String carNum) {
        return signCarDao.getByCarNum(carNum);
    }


}